/**
 * 支持父级，自定义父级，以及window作为父级
 * 使用示例：
 * 1. v-dragable
 * 2. v-dragable="'father'" // 使用父级作为父级
 * 3. v-dragable="'body'" // 使用body对象作为父级
 * 4. v-dragable="'#app'" // 使用id作为父级
 * 5. v-dragable="'.list'" // 使用class名作为父级
 * 3-5代表所有可被document.querySelector()解析的参数值
 **/
const directive = {
    mounted: (el, binding) => {
        setParentDom(el, binding, false)
        // 子级元素位置处理
        // 1. 获取父子元素当前位置
        let parentDomRect
        let elDomRect
        let mouseData      = {
            down: { x: 0, y: 0 },
            move: { x: 0, y: 0 },
        }
        let mouseDown      = false
        el.__position__    = {
            x: 0,
            y: 0,
        }
        let bodyUserSelect = "text"
        
        function handleMouseDown(e){
            if(e.button !== 0){
                return
            }
            mouseData.down                                  = {
                x: e.clientX,
                y: e.clientY,
            }
            mouseDown                                       = true
            parentDomRect                                   = el.__parentDom__.getBoundingClientRect()
            elDomRect                                       = el.getBoundingClientRect()
            bodyUserSelect                                  = document.querySelector("body").style.userSelect
            document.querySelector("body").style.userSelect = "none"
        }
        
        function handleMouseMove(e){
            if(!mouseDown){
                return
            }
            mouseData.move = {
                x: e.clientX,
                y: e.clientY,
            }
            setPosition()
        }
        
        function handleMouseUp(e){
            if(mouseDown){
                mouseDown                                       = false
                document.querySelector("body").style.userSelect = bodyUserSelect
            }
        }
        
        // 用于设置el元素的Position位置
        function setPosition(){
            // 通过几何图形计算更佳，我就是通过几何画图计算出来的当前数据，使用者可以自行计算，得到这两个值
            const x = mouseData.move.x + elDomRect.x - parentDomRect.x - mouseData.down.x
            const y = mouseData.move.y + elDomRect.y - parentDomRect.y - mouseData.down.y
            // 进行x,y坐标边界处理判断
            if(x < 0){
                el.__position__.x = 0
            }
            else if(x > parentDomRect.width - elDomRect.width){
                el.__position__.x = parentDomRect.width - elDomRect.width
            }
            else{
                el.__position__.x = x
            }
            if(y < 0){
                el.__position__.y = 0
            }
            else if(y > parentDomRect.height - elDomRect.height){
                el.__position__.y = parentDomRect.height - elDomRect.height
            }
            else{
                el.__position__.y = y
            }
            // 渲染到真实dom属性上
            el.style.cssText += `
        position: absolute;
        z-index: 100;
        left: ${ el.__position__.x }px;
        top: ${ el.__position__.y }px;
      `
        }
        
        el.__mouseDown__ = handleMouseDown
        el.__mouseMove__ = handleMouseMove
        el.__mouseUp__   = handleMouseUp
        // 2. 监听拖拽事件
        el.addEventListener("mousedown", el.__mouseDown__)
        document.addEventListener("mousemove", el.__mouseMove__)
        document.addEventListener("mouseup", el.__mouseUp__)
    },
    updated(el, binding){
        setParentDom(el, binding, true)
    },
    beforeUnmount(el){
        // 避免重复开销，卸载所有的监听
        // 解决问题：多次创建新的实例 =》 监听不取消 =》 同时存在多个无用的监听，导致页面性能变差
        document.removeEventListener("mousedown", el.__mouseDown__)
        document.removeEventListener("mousemove", el.__mouseMove__)
        document.removeEventListener("mouseup", el.__mouseUp__)
    },
}

// 设置parentDom，供mounted和update使用
function setParentDom(el, binding, updated){
    
    const array = [
        { name: "father", dom: el.parentElement },
    ]
    
    // 获取父级元素
    let parentDom
    // 以下if操作用于确保一定有一个parentDom
    if(binding.value){
        const findArr = array.find((arr) => {
            return arr.name === binding.value
        })
        if(findArr && findArr.dom){
            parentDom = findArr.dom
        }
        else{
            parentDom = document.querySelector(binding.value) || array[0].dom || array[1].dom
        }
    }
    else{
        parentDom = array[0].dom || array[1].dom
    }
    const parentDomRect = parentDom.getBoundingClientRect()
    const elDomRect     = el.getBoundingClientRect()
    // 把以前的样式重置一下
    if(el.__parentDom__){
        el.__parentDom__.style.position = "static"
    }
    el.__parentDom__                = parentDom
    el.__parentDom__.style.position = "relative"
    
    if(updated){
        el.__position__ = {
            x: elDomRect.x - parentDomRect.x,
            y: elDomRect.y - parentDomRect.y,
        }
        // return
        el.style.cssText += `
      position: absolute;
      z-index: 100;
      left: ${ el.__position__.x }px;
      top: ${ el.__position__.y }px;
    `
    }
}

export default directive
